/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.facebook.fresco.helper.utils;


import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import com.oszc.bbhmlibrary.wrapper.TextUtils;

/**
 * 打印LOG，用于调试，可直接定位到行数
 * mlog
 *
 * @version 1.0
 * @since 2021-07-29
 */
public class MLog {
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x01, "fresco-helper");
    private static final String DEFAULT_MESSAGE = "execute";
    private static final String PARAM = "Param";
    private static final String NULL = "null";
    private static final String TAG_DEFAULT = "MLog";
    private static final String SUFFIX = ".java";
    private static boolean isShowLog = true;
    private static final int MIN_STACK_OFFSET = 5;
    private static String mGlobalTag;

    private MLog() {
    }

    /**
     * 初始化
     *
     * @param tag 标签
     * @param show 显示日志
     */
    public static void init(String tag, boolean show) {
        MLog.isShowLog = show;
        mGlobalTag = tag;
    }

    /**
     * vv
     */
    public static void vv() {
        printLog(HiLog.DEBUG, null, DEFAULT_MESSAGE);
    }

    /**
     * vv
     *
     * @param msg 味精
     */
    public static void vv(Object msg) {
        printLog(HiLog.DEBUG, null, msg);
    }

    /**
     * vv
     *
     * @param tag 标签
     * @param objects 对象
     */
    public static void vv(String tag, Object... objects) {
        printLog(HiLog.DEBUG, tag, objects);
    }

    /**
     * 调试
     */
    public static void debug() {
        printLog(HiLog.DEBUG, null, DEFAULT_MESSAGE);
    }

    /**
     * 调试
     *
     * @param msg 味精
     */
    public static void debug(Object msg) {
        printLog(HiLog.DEBUG, null, msg);
    }

    /**
     * 调试
     *
     * @param tag 标签
     * @param objects 对象
     */
    public static void debug(String tag, Object... objects) {
        printLog(HiLog.DEBUG, tag, objects);
    }

    /**
     * 信息
     */
    public static void info() {
        printLog(HiLog.INFO, null, DEFAULT_MESSAGE);
    }

    /**
     * 信息
     *
     * @param msg 味精
     */
    public static void info(Object msg) {
        printLog(HiLog.INFO, null, msg);
    }

    /**
     * 信息
     *
     * @param tag 标签
     * @param objects 对象
     */
    public static void info(String tag, Object... objects) {
        printLog(HiLog.INFO, tag, objects);
    }

    /**
     * 警告
     */
    public static void warn() {
        printLog(HiLog.WARN, null, DEFAULT_MESSAGE);
    }

    /**
     * 警告
     *
     * @param msg 味精
     */
    public static void warn(Object msg) {
        printLog(HiLog.WARN, null, msg);
    }

    /**
     * 警告
     *
     * @param tag 标签
     * @param objects 对象
     */
    public static void warn(String tag, Object... objects) {
        printLog(HiLog.WARN, tag, objects);
    }

    /**
     * 错误
     */
    public static void error() {
        printLog(HiLog.ERROR, null, DEFAULT_MESSAGE);
    }

    /**
     * 错误
     *
     * @param msg 味精
     */
    public static void error(Object msg) {
        printLog(HiLog.ERROR, null, msg);
    }

    /**
     * 错误
     *
     * @param tag 标签
     * @param objects 对象
     */
    public static void error(String tag, Object... objects) {
        printLog(HiLog.ERROR, tag, objects);
    }

    /**
     * 打印日志
     *
     * @param type 类型
     * @param tagStr 标记str
     * @param objects 对象
     */
    private static void printLog(int type, String tagStr, Object... objects) {
        if (!isShowLog) {
            return;
        }

        String[] contents = wrapperContent(tagStr, objects);
        String tag = contents[0];
        String msg = contents[1];
        String headString = contents[2];
        printDefault(type, tag, headString + System.lineSeparator() + msg);
    }

    /**
     * 包装内容
     *
     * @param tagStr 标记str
     * @param objects 对象
     * @return {@link String}
     */
    private static String[] wrapperContent(String tagStr, Object... objects) {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        checkNotNull(stackTrace);

        int stackOffset = MIN_STACK_OFFSET;
        for (int ii = MIN_STACK_OFFSET; ii < stackTrace.length; ii++) {
            StackTraceElement e = stackTrace[ii];
            String name = e.getClassName();
            if (!name.equals(MLog.class.getName())) {
                stackOffset = ii;
                break;
            }
        }

        StackTraceElement targetElement = stackTrace[stackOffset];
        String className = targetElement.getClassName();
        String[] classNameInfo = className.split("\\.");
        if (classNameInfo.length > 0) {
            className = classNameInfo[classNameInfo.length - 1] + SUFFIX;
        }

        if (className.contains("$")) {
            className = className.split("\\$")[0] + SUFFIX;
        }

        String methodName = targetElement.getMethodName();
        int lineNumber = targetElement.getLineNumber();

        if (lineNumber < 0) {
            lineNumber = 0;
        }

        String methodNameShort = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);

        /**
         * 支持全局TAG和局部TAG混搭
         *
         * 示例：
         * KLog.i("使用全局的TAG");
         KLog.i("Test", "使用局部的TAG");
         执行结果：
         I/BoloLog: [ (Method.java:0)#Invoke ] 使用全局的TAG
         I/Test: [ (Method.java:0)#Invoke ] 使用局部的TAG
         **/
        String tag = tagStr;
        if (TextUtils.isEmpty(tag)) {
            if (!TextUtils.isEmpty(mGlobalTag)) {
                tag = mGlobalTag;
            } else {
                tag = TAG_DEFAULT;
            }
        }

        String msg = getObjectsString(objects);
        String headString = "[ (" + className + ":" + lineNumber + ")-->" + methodNameShort + " ] ";

        return new String[]{tag, msg, headString};
    }

    /**
     * 获得对象的字符串
     *
     * @param objects 对象
     * @return {@link String}
     */
    private static String getObjectsString(Object... objects) {
        if (objects.length > 1) {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(System.lineSeparator());
            for (int i = 0; i < objects.length; i++) {
                Object object = objects[i];
                if (object == null) {
                    stringBuilder.append(PARAM).append("[")
                        .append(i).append("]").append(" = ").append(NULL).append(System.lineSeparator());
                } else {
                    stringBuilder.append(PARAM).append("[")
                        .append(i).append("]").append(" = ").append(object.toString()).append(System.lineSeparator());
                }
            }
            return stringBuilder.toString();
        } else {
            Object object = objects[0];
            return object == null ? NULL : object.toString();
        }
    }

    /**
     * 打印默认
     *
     * @param type 类型
     * @param tag 标签
     * @param msg 味精
     */
    private static void printDefault(int type, String tag, String msg) {
        int index = 0;
        int maxLength = 4000;
        int countOfSub = msg.length() / maxLength;

        if (countOfSub > 0) {
            for (int i = 0; i < countOfSub; i++) {
                String sub = msg.substring(index, index + maxLength);
                printSub(type, tag, sub);
                index += maxLength;
            }
            printSub(type, tag, msg.substring(index, msg.length()));
        } else {
            printSub(type, tag, msg);
        }
    }

    /**
     * 打印的子
     *
     * @param type 类型
     * @param tag 标签
     * @param sub 子
     */
    private static void printSub(int type, String tag, String sub) {
        switch (type) {
            case HiLog.DEBUG:
                HiLog.debug(LABEL,tag, sub);
                break;
            case HiLog.INFO:
                HiLog.info(LABEL,tag, sub);
                break;
            case HiLog.WARN:
                HiLog.warn(LABEL,tag, sub);
                break;
            case HiLog.ERROR:
                HiLog.error(LABEL,tag, sub);
                break;
            default:
                break;
        }
    }

    /**
     * 检查非空
     *
     * @param obj obj
     * @return {@link T}
     */
    private static <T> T checkNotNull(final T obj) {
        if (obj == null) {
            throw new NullPointerException();
        }
        return obj;
    }
}